﻿#include "catimgui.h"
#include "imgui.h"
#include "imgui_impl_glfw.h"
#include "imgui_impl_opengl3.h"

#include "ImGuiColorTextEdit/TextEditor.h"
#include "imgui_markdown/imgui_markdown.h"
#include "IconFontCppHeaders/IconsFontAwesome5.h"
#include "notification/NotificationIcon.hpp"

#include "../../libcat/include/cat.hpp"
#include "../../libcat/include/util/base.hpp"
#include "../../libcat/include/util/json.h"
#include "../../libcat/include/util/jsoncpp.cpp"
#include "../../libcat/include/util/platform.hpp"
#include "../../libcat/include/util/utf8.h"
#include "../../libcat/include/util/cmem.hpp"

#include "../../liblive2d/include/catlive2d.hpp"

#define STB_IMAGE_IMPLEMENTATION
#define STBI_WINDOWS_UTF8
#include "../../deps/stb/stb_image.h"

#include "cat-client.hpp"
#include "portable-file-dialogs.h"

#include <SFML/Graphics.hpp>
#include <fstream>

// About Desktop OpenGL function loaders:
//  Modern desktop OpenGL doesn't have a standard portable header file to load OpenGL function pointers.
//  Helper libraries are often used for this purpose! Here we are supporting a few common ones (gl3w, glew, glad).
//  You may use another loader/header of your choice (glext, glLoadGen, etc.), or chose to manually implement your own.
#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
#include <GL/gl3w.h>            // Initialize with gl3wInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
#include <GL/glew.h>            // Initialize with glewInit()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
#include <glad/glad.h>          // Initialize with gladLoadGL()
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
#define GLFW_INCLUDE_NONE       // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/Binding.h>  // Initialize with glbinding::Binding::initialize()
#include <glbinding/gl/gl.h>
using namespace gl;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
#define GLFW_INCLUDE_NONE       // GLFW including OpenGL headers causes ambiguity or multiple definition errors.
#include <glbinding/glbinding.h>// Initialize with glbinding::initialize()
#include <glbinding/gl/gl.h>
using namespace gl;
#else
#include IMGUI_IMPL_OPENGL_LOADER_CUSTOM
#endif

// Include glfw3.h after our OpenGL definitions
#define GLFW_EXPOSE_NATIVE_WIN32
#include <windows.h>
#include <GLFW/glfw3.h>
#include <GLFW/glfw3native.h>

#include <imgui_internal.h>


// [Win32] Our example includes a copy of glfw3.lib pre-compiled with VS2010 to maximize ease of testing and compatibility with old VS compilers.
// To link with VS2010-era libraries, VS2015+ requires linking with legacy_stdio_definitions.lib, which we do using this pragma.
// Your own project should not be affected, as you are likely to link with a newer binary of GLFW that is adequate for your version of Visual Studio.
#if defined(_MSC_VER) && (_MSC_VER >= 1900) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#pragma comment(lib, "legacy_stdio_definitions")
#endif

static void glfw_error_callback(int error, const char* description)
{
    fprintf(stderr, "Glfw Error %d: %s\n", error, description);
}


static void HelpMarker(const char* desc)
{
    ImGui::TextDisabled("(?)");
    if (ImGui::IsItemHovered())
    {
        ImGui::BeginTooltip();
        ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f);
        ImGui::TextUnformatted(desc);
        ImGui::PopTextWrapPos();
        ImGui::EndTooltip();
    }
}

void LinkCallback(ImGui::MarkdownLinkCallbackData data_);

inline ImGui::MarkdownImageData ImageCallback(ImGui::MarkdownLinkCallbackData data_);

// You can make your own Markdown function with your prefered string container and markdown config.
static ImGui::MarkdownConfig mdConfig{ LinkCallback, ImageCallback, "", { { NULL, true }, { NULL, true }, { NULL, false } } };

void LinkCallback(ImGui::MarkdownLinkCallbackData data_)
{
    std::string url(data_.link, data_.linkLength);
    if (!data_.isImage)
    {
        ShellExecuteA(NULL, "open", url.c_str(), NULL, NULL, SW_SHOWNORMAL);
    }
} 
struct myImg {
    int image_width;
    int image_height;
    GLuint image_texture;
};


static std::map<std::string, myImg> img_holder;

bool LoadTextureFromFile(const char* filename, GLuint* out_texture, int* out_width, int* out_height)
{
    int image_width = 0;
    int image_height = 0;

    unsigned char* image_data = stbi_load(filename, &image_width, &image_height, NULL, 4);;
    if (image_data == NULL)
        return false;

    // Create a OpenGL texture identifier
    GLuint image_texture;
    glGenTextures(1, &image_texture);
    glBindTexture(GL_TEXTURE_2D, image_texture);

    // Setup filtering parameters for display
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // Upload pixels into texture
    glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
    stbi_image_free(image_data);

    *out_texture = image_texture;
    *out_width = image_width;
    *out_height = image_height;

    return true;
}

static myImg * load_texture(std::string path) {
    if (img_holder.find(path) == img_holder.end()) {
        LoadTextureFromFile(path.c_str(), &img_holder[path].image_texture, &img_holder[path].image_width, &img_holder[path].image_height);      
    }
    return &img_holder[path];
}

inline ImGui::MarkdownImageData ImageCallback(ImGui::MarkdownLinkCallbackData data_)
{
    myImg* mytexture = load_texture(std::string(data_.link, data_.linkLength));
    ImGui::MarkdownImageData imageData{ true, false, (void*)(intptr_t)mytexture->image_texture, ImVec2(mytexture->image_width, mytexture->image_height) }; 
    imageData.isValid = true;
    return imageData;
}

void LoadFonts()
{
    ImGuiIO& io = ImGui::GetIO();
    io.Fonts->Clear();
    // Base font
    ImFont* font = io.Fonts->AddFontFromFileTTF(u8"Resources/local/cat.ttf", 22.0f, NULL, io.Fonts->GetGlyphRangesChineseFull()); 
    ImFont* headerFont = io.Fonts->AddFontFromFileTTF(u8"Resources/local/cat.ttf", 33.0f, NULL, io.Fonts->GetGlyphRangesChineseSimplifiedCommon());
    // Bold headings H2 and H3
    mdConfig.headingFormats[1].font = font;
    mdConfig.headingFormats[2].font = headerFont;
    // bold heading H1
    mdConfig.headingFormats[0].font = font;
}

void Markdown(const std::string& markdown_)
{
    // fonts for, respectively, headings H1, H2, H3 and beyond
    ImGui::Markdown(markdown_.c_str(), markdown_.length(), mdConfig);
}

char* LoadFile(const char* path)
{
    //fix open wchar file path   
    wchar_t* wstr = (wchar_t*)bmalloc(255);
    size_t wstrsize = utf8_to_wchar(path,0, wstr,255);
    wstr[wstrsize] = '\0';

    int size = 0;
    struct _stat64 statBuf;
    if (_wstat64(wstr, &statBuf) == 0)
    {
        size = statBuf.st_size;
    }
    else {
        size = 0;
    }
    std::fstream file;
    char* buf = (char*)bmalloc(size+1);
    buf[size] = 0x00;
    file.open(wstr, std::ios::in | std::ios::binary);
    if (!file.is_open())
    {
        return NULL;
    }
    file.read(buf, size);
    file.close();
    bfree(wstr);    
    return buf;
}

static void load_module_decelaration(cat_data* cfg,int module_id) {
    std::string standard_module_path;
    for (auto entry = cfg->json["plugins"]["mode_ex"].begin(); entry != cfg->json["plugins"]["mode_ex"].end(); entry++) {
        if ((*entry).isNull()|| (*entry)["module_id"].isNull())
            continue;
        if (module_id == (*entry)["module_id"].asInt()) {
            standard_module_path = (*entry)["module_data_path"].asString();
            break;
        }       
    }
    char* data = LoadFile(standard_module_path.c_str());
    if (data == NULL)
    {
        return;
    }

    JSONCPP_STRING error;
    Json::CharReaderBuilder json_builder;
    Json::Value root;
    Json::CharReader* json_reader = json_builder.newCharReader();
    bool parsingSuccessful = json_reader->parse(data, data + strlen(data), &root, &error);
    if (!parsingSuccessful) {
        return;
    }
    delete json_reader;
    bfree(data);

    cfg->json["decoration"]["window_size"][0] = root["decoration"]["window_size"][0].asInt();
    cfg->json["decoration"]["window_size"][1] = root["decoration"]["window_size"][1].asInt();

    cfg->json["decoration"]["l2d_correct"]= root["decoration"]["l2d_correct"].asFloat();
    cfg->json["decoration"]["l2d_offset"][0]= root["decoration"]["l2d_offset"][0].asFloat();
    cfg->json["decoration"]["l2d_offset"][1]= root["decoration"]["l2d_offset"][1].asFloat();

    cfg->json["decoration"]["armLineColor"][0] = root["decoration"]["armLineColor"][0].asInt();
    cfg->json["decoration"]["armLineColor"][1] = root["decoration"]["armLineColor"][1].asInt();
    cfg->json["decoration"]["armLineColor"][2] = root["decoration"]["armLineColor"][2].asInt();

    cfg->json["decoration"]["hand_offset"][0] = root["decoration"]["hand_offset"][0].asInt();
    cfg->json["decoration"]["hand_offset"][1] = root["decoration"]["hand_offset"][1].asInt();;

}

static void DataSender(CatClient &client,int action,cat_data *data) {
    Json::FastWriter fastWriter;
    std::string output = fastWriter.write(data->json);
    client.SendData(action,(char*)output.c_str(),output.size());
}

static bool updateJson(Json::Value& cfg_default, Json::Value& cfg)
{
    bool is_update = true;
    for (const auto& key : cfg.getMemberNames())
        if (cfg_default.isMember(key))
        {
            if (cfg_default[key].type() != cfg[key].type())
            {
                return false;
            }
            if (cfg_default[key].isArray())
                for (Json::Value& v : cfg[key])
                    if (v.type() != cfg_default[key][0].type())
                    {
                        return false;
                    }
            if (cfg_default[key].isObject())
                is_update &= updateJson(cfg_default[key], cfg[key]);
            else
                cfg_default[key] = cfg[key];
        }
    return is_update;
}

static bool isShowTool = true;

static bool isShowSettiong = false;

static bool Exist = false;

void catimgui::Run(int port)
{
    CatClient *client = CatClient::GetInstance();
    client->SetClientPort(port);

    NotificationIcon::GetInstance()->Start();

    cat_live2d_initailize();    

    const char* glsl_version = "#version 130";
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
    glfwWindowHint(GLFW_VISIBLE, GL_TRUE);
    glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);
    glfwWindowHint(GLFW_DECORATED, GL_FALSE);
    glfwWindowHint(GLFW_FOCUSED, GL_FALSE);
    //glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, GL_TRUE);
    // Create window with graphics context
    GLFWwindow* window = glfwCreateWindow(120, 65, u8"Bongo Cat 设置", NULL, NULL);
    if (window == NULL)
        return;  

    glfwMakeContextCurrent(window);
    glfwSwapInterval(1); // Enable vsync
    int position_x = 0;
    int position_y = 0;
    glfwGetWindowPos(window, &position_x, &position_y); 
    glfwSetWindowPos(window, -120,-65);
    glfwShowWindow(window);

    sf::Image icon;
    icon.loadFromFile("Resources/bongocat.png"); 
    GLFWimage icons[1];
    icons[0].width = icon.getSize().x;
    icons[0].height = icon.getSize().y;
    icons[0].pixels = (unsigned char*)icon.getPixelsPtr();
    glfwSetWindowIcon(window, 1, icons);

#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
    bool err = gl3wInit() != 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
    bool err = glewInit() != GLEW_OK;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
    bool err = gladLoadGL() == 0;
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
    bool err = false;
    glbinding::Binding::initialize();
#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
    bool err = false;
    glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); });
#else
    bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
#endif
    if (err)
    {
        fprintf(stderr, "Failed to initialize OpenGL loader!\n");
        return;
    }

    // Setup Dear ImGui context
    IMGUI_CHECKVERSION();
    ImGui::CreateContext();
    ImGuiIO& io = ImGui::GetIO(); (void)io;
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
    //ImFont* font = io.Fonts->AddFontFromFileTTF("Resources/cat.ttf", 22.0f, NULL, io.Fonts->GetGlyphRangesChineseFull());
    io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;       // Enable Keyboard Controls
    //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad;      // Enable Gamepad Controls
    io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;           // Enable Docking
    io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;         // Enable Multi-Viewport / Platform Windows

    LoadFonts();    
    // Setup Dear ImGui style
    ImGui::StyleColorsDark();

    ImGuiStyle& style = ImGui::GetStyle();
    if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
    {
        style.WindowRounding = 0.0f;
        style.Colors[ImGuiCol_WindowBg].w = 1.0f;
    }
    style.GrabRounding = 8.0f;
    style.FrameRounding = 8.0f; 
    style.Alpha = 1.f;
    // Setup Platform/Renderer bindings
    ImGui_ImplGlfw_InitForOpenGL(window, true);
    ImGui_ImplOpenGL3_Init(glsl_version);
   
    ImGuiWindowFlags window_flags = 0;
    window_flags |= ImGuiWindowFlags_NoCollapse; 
    window_flags |= ImGuiWindowFlags_NoTitleBar;
#ifndef _DEBUG
    //window_flags |= ImGuiWindowFlags_NoMove;
    window_flags |= ImGuiWindowFlags_NoResize;
#endif // !_DEBUG  
    /***********************************************/

    TextEditor editor;
    auto lang = TextEditor::LanguageDefinition::Json();
    // set your own identifiers

    static const char* identifiers[] = {
        "16","17","18","19","20" ,"32","33","34","35","36","37","38","39","40","41","42","43","44","45","46","47",
        "48","49","50","51","52","53","54","55","56","57","65","66","67","68","69","70","71","72","73","74","75","76",
        "77","78","79","80","81","82","83","84","85","86","87","88","89","90","91","92","93","94","95","96","97","98",
        "99","100","101","102","103","104","105","106","107","108","109","110","111","112","113","114","115","116","117",
        "118","119","120","121","122","123","124","125","126","127","144","145","160","161","162","163","164","165" };

    static const char* idecls[] =
    {
        "SHIFT","CTRL","ALT","PAUSE","CAPS LOCK","SPACE", "PAGE UP","PAGE DOWN","END","HOME","LEFT","UP","RIGHT","DOWN",
        "SELECT","PRINT","EXECUTE","PRINT SCREEN","INS","DEL","HELP","0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G",
    "H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","Left Windows key","Right Windows key","Applications key",
    "Reserved","Computer Sleep","Numeric keypad 0","Numeric keypad 1","Numeric keypad 2","Numeric keypad 3","Numeric keypad 4",
    "Numeric keypad 5","Numeric keypad 6","Numeric keypad 7","Numeric keypad 8","Numeric keypad 9","Multiply","Add","Separator",
    "Subtract","Decimal","Divide","F1","F2","F3","F4","F5","F6","F7","F8","F9","F10","F11","F12","F13","F14","F15","F16",
    "NUM LOCK","SCROLL LOCK","Left SHIFT","Right SHIFT","Left CONTROL","Right CONTROL","Left ALT","Right ALT" };
    for (int i = 0; i < sizeof(identifiers) / sizeof(identifiers[0]); ++i)
    {
        TextEditor::Identifier id;
        id.mDeclaration = std::string(idecls[i]);
        lang.mIdentifiers.insert(std::make_pair(std::string(identifiers[i]), id));
    }
    static const char* modeIdentifiers[] = {
    "\"standard\"","\"keyboard\"","\"gamepad\"","\"face\"","\"hand\""
    ,"\"l2d_expression\"","\"l2d_motion\"","\"sounds\""
    ,"\"lefthand\"","\"righthand\""
    };
    static const char* modeIdecls[] = {
       u8"标准模式",u8"键盘模式或键盘",u8"手柄模式",u8"普通表情",u8"手",
       u8"Live2D表情",u8"Live2D动作",u8"声音",u8"左手",u8"右手"
    };
    for (int i = 0; i < sizeof(modeIdentifiers) / sizeof(modeIdentifiers[0]); ++i)
    {
        TextEditor::Identifier id;
        id.mDeclaration = std::string(modeIdecls[i]);
        lang.mIdentifiers.insert(std::make_pair(std::string(modeIdentifiers[i]), id));
    }

    editor.SetLanguageDefinition(lang);

    /***********************************************/
    cat_data* cfg =cat_data_create_from_json_file("config.ini");
      
    int mode = cfg->json["plugins"]["mode"].asInt();
    /***********************************************/
    //背景颜色
    ImVec4 clear_color = ImVec4(
        static_cast<float>(cfg->json["main_decoration"]["rgb"][0].asInt())/255.0
        ,static_cast<float>(cfg->json["main_decoration"]["rgb"][1].asInt()) / 255.0
        ,static_cast<float>(cfg->json["main_decoration"]["rgb"][2].asInt()) / 255.0
        ,static_cast<float>(cfg->json["main_decoration"]["rgb"][3].asInt()) / 255.0);
    /***********************************************/
    //窗口设置
    int framerateLimit = cfg->json["main_decoration"]["framerateLimit"].asInt();
    bool topWindow = cfg->json["main_decoration"]["topWindow"].asBool();
    
    /***********************************************/
    //鼠标设置;
    bool mousePass = cfg->json["main_decoration"]["is_mouse_through"].asBool();
    bool mouse_horizontal_flip = cfg->json["main_decoration"]["mouse_horizontal_flip"].asBool();
    bool mouse_vertical_flip = cfg->json["main_decoration"]["mouse_vertical_flip"].asBool();
    bool mouse_force_move = cfg->json["main_decoration"]["mouse_force_move"].asBool();
    float mouse_speed = cfg->json["main_decoration"]["mouse_speed"].asFloat();
    /***********************************************/
    //声音设置
    bool silent = cfg->json["main_decoration"]["silent"].asBool();
    int elem1 = cfg->json["main_decoration"]["sound_keep"].asBool() ? 0 : 1; 
    /***********************************************/
    //其他设置
    int elem = cfg->json["main_decoration"]["motion_keep"].asBool() ? 0 : 1;
    /***********************************************/
    
    bool l2d = cfg->json["main_decoration"]["l2d"].asBool();
    float l2d_spead = cfg->json["main_decoration"]["l2d_spead"].asFloat();  
    bool l2d_random_motion = cfg->json["main_decoration"]["l2d_random_motion"].asBool();
    bool l2d_random_expression = cfg->json["main_decoration"]["l2d_random_expression"].asBool();
    /***********************************************/
    //手柄设置
    int gamepad_ID = cfg->json["main_decoration"]["gamepad_ID"].asInt();
    int input_mode = cfg->json["main_decoration"]["input_mode"].asInt();

    /***********************************************/
    load_module_decelaration(cfg,mode);

    float l2d_scale = cfg->json["decoration"]["l2d_correct"].asFloat();
    float l2d_position_x = cfg->json["decoration"]["l2d_offset"][0].asFloat();
    float l2d_position_y = cfg->json["decoration"]["l2d_offset"][1].asFloat();
  
    ImVec4 rightarmLine = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
    rightarmLine.x = static_cast<float>(cfg->json["decoration"]["armLineColor"][0].asInt()) / 255.0;
    rightarmLine.y = static_cast<float>(cfg->json["decoration"]["armLineColor"][1].asInt()) / 255.0;
    rightarmLine.z = static_cast<float>(cfg->json["decoration"]["armLineColor"][2].asInt()) / 255.0;

    int hand_position_x = cfg->json["decoration"]["hand_offset"][0].asInt();
    int hand_position_y = cfg->json["decoration"]["hand_offset"][1].asInt(); 
    /***********************************************/ 
    HWND MainWindowHandle = (HWND)cfg->json["main_decoration"]["window_handle"].asInt64();

    HWND hwn = glfwGetWin32Window(window);
    DWORD windowsStyle = GetWindowLong(hwn, GWL_EXSTYLE);
    SetWindowLong(hwn, GWL_EXSTYLE, windowsStyle | WS_EX_TOOLWINDOW);   
#ifdef _WIN32
    cfg->json["main_decoration"]["window_handle"] = (long)hwn;
#endif  
    DataSender(*client, ToolWindow, cfg);
    /***********************************************/
    static std::shared_ptr<pfd::open_file> open_file;
    bool saveFile = false;
    bool saveFileError = false;   

    

    sf::Clock heart;
    heart.restart();

    bool isShowSettingRecord = isShowSettiong;
    bool isShowToolRecord = isShowTool;
    while (!Exist)
    {             
        if (glfwWindowShouldClose(window)) {
            glfwSetWindowShouldClose(window,false);            
            isShowSettiong = false;
        }

        bool isHostLive = true;
        if (heart.getElapsedTime() > sf::seconds(1))
        {
            isHostLive = client->SendData(HeartBeat, "", 0);
            heart.restart();
        }

        if (!isHostLive) {
            break;
        }

        
        glfwPollEvents();

        // Start the Dear ImGui frame
        ImGui_ImplOpenGL3_NewFrame();
        ImGui_ImplGlfw_NewFrame();
        ImGui::NewFrame();
        /*
        if (isShowSettingRecord != isShowSettiong) {
            isShowSettiong ? glfwShowWindow(window) : glfwHideWindow(window);
            isShowSettingRecord = isShowSettiong;
        }*/

        if (isShowToolRecord != isShowTool) {
            isShowTool ? glfwShowWindow(window) : glfwHideWindow(window);
            isShowToolRecord = isShowTool;
        }
        //这里放ui的逻辑
        {
            static unsigned short ShowWhat = 1;            

            static bool isShowEditor = false;

            static std::string modePath; 

            static RECT rct;             

            //ImGui::ShowDemoWindow(0);
            if (isShowSettiong) 
            {
            ImGui::Begin(u8"选择", 0, window_flags| ImGuiWindowFlags_NoBackground);
            ImGui::SetWindowSize(ImVec2(1280, 760), ImGuiCond_Always);
            ImGui::BeginChild("child1", ImVec2(320, 743), true);
            {   
                ImGui::PushFont(mdConfig.headingFormats[2].font);
                if (ImGui::ButtonEx(u8"基础设置", ImVec2(300, 80), ImGuiButtonFlags_MouseButtonMask_)) {
                    ShowWhat = 1;
                } 

                ImGui::ItemSize(ImVec2(0, 10));
                
                if (ImGui::ButtonEx(u8"模式选择", ImVec2(300, 80), ImGuiButtonFlags_MouseButtonMask_)) {
                    ShowWhat = 2;
                }

                ImGui::ItemSize(ImVec2(0, 10));               

                if (ImGui::ButtonEx(u8"插件设置", ImVec2(300, 80), ImGuiButtonFlags_MouseButtonMask_)) {
                    ShowWhat = 4;
                }

                ImGui::ItemSize(ImVec2(0, 10));

                if (ImGui::ButtonEx(u8"使用教程", ImVec2(300, 80), ImGuiButtonFlags_MouseButtonMask_)) {
                    ShowWhat = 8;
                }
                ImGui::ItemSize(ImVec2(0, 10));

                if (ImGui::ButtonEx(u8"关于软件", ImVec2(300, 80), ImGuiButtonFlags_MouseButtonMask_)) {
                    ShowWhat = 16;
                }
                ImGui::ItemSize(ImVec2(0, 10));

                if (ImGui::ButtonEx(u8"退出设置", ImVec2(300, 80), ImGuiButtonFlags_MouseButtonMask_)) {
                    isShowSettiong = false;
                }

                ImGui::PopFont();
            }           
            ImGui::EndChild(); 

            ImGui::SameLine();

                    
            if (ShowWhat & 1) 
            {   ImGui::BeginChild("child2", ImVec2(940, 743), false);

                ImGui::BeginChild(u8"child2c1", ImVec2(490, 740), false);
                {
                ImGui::BeginChild(u8"设置窗口", ImVec2(490,440), true);
                if (ImGui::BeginTabBar(u8"设置Tab"))
                {
                        if (ImGui::BeginTabItem(u8"基础设置"))
                        {
                            ImGui::Text(u8"窗口设置");
                            if (ImGui::SliderInt(u8"帧率", &framerateLimit, 10, 240, u8"FPS X %d")) {
                                cfg->json["main_decoration"]["framerateLimit"] = framerateLimit;
                                DataSender(*client, WindowChange, cfg);
                            }
                            /*
                            if (ImGui::Checkbox(u8"桌宠模式", &deskPet)) {
                                cfg->json["main_decoration"]["desktop_pet"] = deskPet;
                                if (!deskPet) {
                                    mousePass = false;
                                    cfg->json["main_decoration"]["is_mouse_through"] = mousePass;
                                }
                                DataSender(client, WindowChange, cfg);
                            }*/


                            if (ImGui::Checkbox(u8"鼠标穿透", &mousePass)) {
                                cfg->json["main_decoration"]["is_mouse_through"] = mousePass;
                                DataSender(*client, Update, cfg);
                            }


                            if (ImGui::Checkbox(u8"窗口置顶", &topWindow)) {
                                cfg->json["main_decoration"]["topWindow"] = topWindow;
                                DataSender(*client, WindowChange, cfg);
                            }

                            ImGui::Text(u8"鼠标设置");

                            if (ImGui::Checkbox(u8"鼠标移动水平翻转", &mouse_horizontal_flip)) {
                                cfg->json["main_decoration"]["mouse_horizontal_flip"] = mouse_horizontal_flip;
                                DataSender(*client, Update, cfg);
                            }

                            if (ImGui::Checkbox(u8"鼠标移动垂直翻转", &mouse_vertical_flip)) {
                                cfg->json["main_decoration"]["mouse_vertical_flip"] = mouse_vertical_flip;
                                DataSender(*client, Update, cfg);
                            }

                            if (ImGui::Checkbox(u8"鼠标强制移动", &mouse_force_move)) {
                                cfg->json["main_decoration"]["mouse_force_move"] = mouse_force_move;
                                DataSender(*client, Update, cfg);
                            }
                            ImGui::SameLine(); HelpMarker(u8"3D游戏锁鼠标移动时,计算鼠标相对移动距离");
                            if (mouse_force_move)
                            {
                                if (ImGui::SliderFloat(u8"鼠标速度", &mouse_speed, 0.1f, 10.0f, u8"速度 X %.3f")) {
                                    cfg->json["main_decoration"]["mouse_speed"] = mouse_speed;
                                    DataSender(*client, Update, cfg);
                                }
                            }


                            ImGui::Text(u8"声音设置");
                            if (ImGui::Checkbox(u8"静音", &silent)) {
                                cfg->json["main_decoration"]["silent"] = silent;
                                DataSender(*client, Update, cfg);
                            }

                            const char* elems_names1[2] = { u8"重新播放",u8"同时播放" };
                            const char* elem_name1 = (elem1 >= 0 && elem1 < 2) ? elems_names1[elem1] : "Unknown";
                            if (ImGui::SliderInt(u8"声音播放方式", &elem1, 0, 2 - 1, elem_name1)) {
                                elem1 == 0 ? cfg->json["main_decoration"]["sound_keep"] = true : cfg->json["main_decoration"]["sound_keep"] = false;
                                DataSender(*client, Update, cfg);
                            }

                            ImGui::Text(u8"其他设置");
                            const char* elems_names[2] = { u8"按键取消",u8"松手取消" };
                            const char* elem_name = (elem >= 0 && elem < 2) ? elems_names[elem] : "Unknown";
                            if (ImGui::SliderInt(u8"表情取消方式", &elem, 0, 2 - 1, elem_name)) {
                                elem == 0 ? cfg->json["main_decoration"]["motion_keep"] = true : cfg->json["main_decoration"]["motion_keep"] = false;
                                DataSender(*client, Update, cfg);
                            }

                            ImGui::EndTabItem();
                        }
                        ImGui::EndTabBar();
                }
                ImGui::EndChild();

                ImGui::BeginChild(u8"Live2D设置窗口", ImVec2(490,295), true);
                if (ImGui::BeginTabBar(u8"Live2D设置Tab")) {
                     if (ImGui::BeginTabItem(u8"Live2D设置"))
                        {
                            if (ImGui::Checkbox(u8"使用live2D", &l2d)) {
                                cfg->json["main_decoration"]["l2d"] = l2d;
                                DataSender(*client, Update, cfg);

                            }
                            ImGui::Text(u8"按住ctrl进行精确修改");
                            if (!l2d) {
                                if (ImGui::ColorEdit3(u8"手臂边缘色彩", (float*)&rightarmLine))
                                {
                                    cfg->json["decoration"]["armLineColor"][0] = static_cast<int>(rightarmLine.x * 255);
                                    cfg->json["decoration"]["armLineColor"][1] = static_cast<int>(rightarmLine.y * 255);
                                    cfg->json["decoration"]["armLineColor"][2] = static_cast<int>(rightarmLine.z * 255);
                                    DataSender(*client, Update, cfg);
                                }
                                if (ImGui::SliderInt(u8"手X坐标", &hand_position_x, -50, 50, u8" x轴偏移 %d")) {
                                    cfg->json["decoration"]["hand_offset"][0] = hand_position_x;
                                    DataSender(*client, Update, cfg);
                                }
                                if (ImGui::SliderInt(u8"手Y坐标", &hand_position_y, -50, 50, u8" y轴偏移 %d")) {
                                    cfg->json["decoration"]["hand_offset"][1] = hand_position_y;
                                    DataSender(*client, Update, cfg);
                                }
                            }
                            else {
                                if (ImGui::Checkbox(u8"随机动作", &l2d_random_motion)) {
                                    cfg->json["main_decoration"]["l2d_random_motion"] = l2d_random_motion;
                                    if (!l2d_random_motion) {
                                        cfg->json["main_decoration"]["l2d_random_expression"] = false;
                                        l2d_random_expression = false;
                                    }
                                    DataSender(*client, Update, cfg);
                                }
                                ImGui::SameLine(); HelpMarker(u8"注意！此选项会播放所有动作组里的动作");

                                if (l2d_random_motion)
                                    if (ImGui::Checkbox(u8"随机表情", &l2d_random_expression)) {
                                        cfg->json["main_decoration"]["l2d_random_expression"] = l2d_random_expression;
                                        DataSender(*client, Update, cfg);
                                    }
                                if (ImGui::SliderFloat(u8"运动速度", &l2d_spead, 0.0f, 10.0f, u8"速度 X %.4f", 2.0f))
                                {
                                    cfg->json["main_decoration"]["l2d_spead"] = l2d_spead;
                                    DataSender(*client, Update, cfg);
                                }

                                if (ImGui::SliderFloat(u8"伸缩", &l2d_scale, 0.0f, 10.0f, "%.4f", 4.0f))
                                {
                                    cfg->json["decoration"]["l2d_correct"] = l2d_scale;
                                    DataSender(*client, Update, cfg);
                                }

                                if (ImGui::SliderFloat(u8"x 坐标", &l2d_position_x, -1.0f, 1.0f, "%f", 5.0f))
                                {
                                    cfg->json["decoration"]["l2d_offset"][0] = l2d_position_x;
                                    DataSender(*client, Update, cfg);
                                }
                                if (ImGui::SliderFloat(u8"y 坐标", &l2d_position_y, -1.0f, 1.0f, "%f", 5.0f)) {
                                    cfg->json["decoration"]["l2d_offset"][1] = l2d_position_y;
                                    DataSender(*client, Update, cfg);
                                }

                            }

                            if (ImGui::Button(u8"保存设置到json文件"))
                            {
                                saveFile = false;
                                saveFileError = false;

                                std::string standard_module_path;
                                for (auto entry = cfg->json["plugins"]["mode_ex"].begin(); entry != cfg->json["plugins"]["mode_ex"].end(); entry++) {
                                    if ((*entry).isNull()||(*entry)["module_id"].isNull())
                                        continue;
                                    if (mode == (*entry)["module_id"].asInt()) {
                                        standard_module_path = (*entry)["module_data_path"].asString();
                                        break;
                                    }
                                }
                                char* data = LoadFile(standard_module_path.c_str());
                                if (data != NULL) {
                                    saveFile = true;
                                    JSONCPP_STRING error;
                                    Json::CharReaderBuilder json_builder;
                                    Json::Value root;
                                    Json::CharReader* json_reader = json_builder.newCharReader();
                                    bool parsingSuccessful = json_reader->parse(data, data + strlen(data), &root, &error);
                                    if (!parsingSuccessful) {
                                        return;
                                    }
                                    delete json_reader;
                                    bfree(data);
                                    updateJson(root, cfg->json);

                                    wchar_t* wstr = (wchar_t*)bmalloc(255);
                                    size_t wstrsize = utf8_to_wchar(standard_module_path.c_str(), 0, wstr, 255);
                                    wstr[wstrsize] = '\0';

                                    std::ofstream os;
                                    os.open(wstr, std::ios::out | std::ios::trunc);
                                    if (os.good()) {
                                        Json::StreamWriterBuilder builder;
                                        std::unique_ptr<Json::StreamWriter> writer(builder.newStreamWriter());
                                        writer->write(root, &os);
                                    }
                                    os.close();
                                    bfree(wstr);
                                }
                                else {
                                    saveFileError = true;
                                }

                            }
                            if (saveFile) {
                                ImGui::SameLine();
                                ImGui::Text(u8"保存成功");                           
                            }

                            if (saveFileError) {
                                ImGui::SameLine();
                                ImGui::Text(u8"保存失败");                            
                            }

                            ImGui::EndTabItem();
                        }
                    ImGui::EndTabBar();
                }
                ImGui::EndChild();
                }
                ImGui::EndChild();

                ImGui::SameLine();

                ImGui::BeginChild(u8"child2c2", ImVec2(440, 740), false);
                {
                ImGui::BeginChild(u8"背景设置窗口", ImVec2(440,540), true);
                if (ImGui::BeginTabBar(u8"背景设置Tab")) { 
                    if (ImGui::BeginTabItem(u8"背景设置"))
                        {
                            static ImVec4 color = ImVec4(clear_color.x, clear_color.y, clear_color.z, clear_color.w);

                            static bool alpha_preview = true;
                            static bool alpha_half_preview = false;
                            static bool drag_and_drop = true;
                            static bool options_menu = true;
                            static bool hdr = true;
                            ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);

                            ImGui::Text(u8"颜色选取");
                            static bool alpha = true;
                            static bool alpha_bar = true;
                            static bool side_preview = true;
                            static bool ref_color = false;
                            static ImVec4 ref_color_v(1.0f, 0.0f, 1.0f, 0.5f);
                            static int display_mode = 0;
                            static int picker_mode = 0;
                            ImGui::Checkbox(u8"设置透明度", &alpha);
                            ImGui::SameLine(); HelpMarker(u8"设置背景颜色的透明度");
                            alpha_bar = alpha;

                            ImGui::Checkbox(u8"预览", &side_preview);
                            ImGui::Combo(u8"显示模式", &display_mode, u8"自动\0无\0RGB模式\0HSV模式\0十六进制色值\0");
                            ImGui::SameLine(); HelpMarker(u8"显示颜色的数字 RGB HSV 或 16进制");
                            ImGui::Combo(u8"选择模式", &picker_mode, u8"自动\0Hue bar + SV rect\0Hue wheel + SV triangle\0");
                            ImGui::SameLine(); HelpMarker(u8"点击选择器选择背景颜色");
                            ImGuiColorEditFlags flags = misc_flags;
                            if (!alpha)            flags |= ImGuiColorEditFlags_NoAlpha;        // This is by default if you call ColorPicker3() instead of ColorPicker4()
                            if (alpha_bar)         flags |= ImGuiColorEditFlags_AlphaBar;
                            if (!side_preview)     flags |= ImGuiColorEditFlags_NoSidePreview;
                            if (picker_mode == 1)  flags |= ImGuiColorEditFlags_PickerHueBar;
                            if (picker_mode == 2)  flags |= ImGuiColorEditFlags_PickerHueWheel;
                            if (display_mode == 1) flags |= ImGuiColorEditFlags_NoInputs;       // Disable all RGB/HSV/Hex displays
                            if (display_mode == 2) flags |= ImGuiColorEditFlags_DisplayRGB;     // Override display mode
                            if (display_mode == 3) flags |= ImGuiColorEditFlags_DisplayHSV;
                            if (display_mode == 4) flags |= ImGuiColorEditFlags_DisplayHex;
                            if (ImGui::ColorPicker4(u8"色彩##4", (float*)&color, flags, ref_color ? &ref_color_v.x : NULL)) {
                                cfg->json["main_decoration"]["rgb"][0] = static_cast<int>(color.x * 255);
                                cfg->json["main_decoration"]["rgb"][1] = static_cast<int>(color.y * 255);
                                cfg->json["main_decoration"]["rgb"][2] = static_cast<int>(color.z * 255);                                
                                cfg->json["main_decoration"]["rgb"][3] = static_cast<int>(color.w * 255);
                                DataSender(*client, BakeColorChange, cfg);
                            };
                            ImGui::SetColorEditOptions(ImGuiColorEditFlags_Float | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_PickerHueWheel);
                            clear_color = color;
                            ImGui::EndTabItem();
                        }
                ImGui::EndTabBar(); }
                ImGui::EndChild();              

                ImGui::BeginChild(u8"手柄设置窗口", ImVec2(440, 195), true);
                if (ImGui::BeginTabBar(u8"手柄设置Tab")) {
                    if (ImGui::BeginTabItem(u8"手柄设置"))
                    {                     
                        const char* elems_names1[8] = { u8"1",u8"2",u8"3",u8"4",u8"5",u8"6",u8"7",u8"8" };
                        const char* elem_name1 = (gamepad_ID >= 0 && gamepad_ID < 8) ? elems_names1[gamepad_ID] : "Unknown";
                        if (ImGui::SliderInt(u8"手柄ID", &gamepad_ID, 0, 8 - 1, elem_name1)) {
                            cfg->json["main_decoration"]["gamepad_ID"] = gamepad_ID;
                            DataSender(*client, Update, cfg);
                        }
                        ImGui::EndTabItem();
                    }
                    ImGui::EndTabBar();
                }
                ImGui::EndChild();
                }
                ImGui::EndChild();
            }
            else
            {
                ImGui::BeginChild("child2", ImVec2(940,743), true);
            }

            if (ShowWhat & 2)
            {

                //ImGui::Begin(u8"模式选择窗口", 0, window_flags);
                {
                    ImGui::Text(u8"模式列表:");

                    for (auto entry = cfg->json["plugins"]["mode_ex"].begin(); entry != cfg->json["plugins"]["mode_ex"].end(); entry++) {
                        if ((*entry).isNull() || (*entry)["module_id"].isNull())
                            continue;
                        if (mode == (*entry)["module_id"].asInt()) {
                            ImGui::Text(u8"当前模式:%s", (*entry)["module_name"].asCString());
                            if (!(*entry)["active"].asBool()) {
                                (*entry)["active"] = true;
                                load_module_decelaration(cfg, mode);

                                l2d_scale = cfg->json["decoration"]["l2d_correct"].asFloat();
                                l2d_position_x = cfg->json["decoration"]["l2d_offset"][0].asFloat();
                                l2d_position_y = cfg->json["decoration"]["l2d_offset"][1].asFloat();

                                rightarmLine.x = static_cast<float>(cfg->json["decoration"]["armLineColor"][0].asInt()) / 255.0;
                                rightarmLine.y = static_cast<float>(cfg->json["decoration"]["armLineColor"][1].asInt()) / 255.0;
                                rightarmLine.z = static_cast<float>(cfg->json["decoration"]["armLineColor"][2].asInt()) / 255.0;

                                hand_position_x = cfg->json["decoration"]["hand_offset"][0].asInt();
                                hand_position_y = cfg->json["decoration"]["hand_offset"][1].asInt();

                                DataSender(*client, ModeChange, cfg);
                            }
                        }
                        else {
                            (*entry)["active"] = false;
                        }
                    }
                    ImGui::Separator();

                    for (auto entry = cfg->json["plugins"]["mode_ex"].begin(); entry != cfg->json["plugins"]["mode_ex"].end(); entry++) {
                        if ((*entry).isNull() || (*entry)["module_id"].isNull())
                            continue;
                        ImGui::Text(u8"模式名称:%s", (*entry)["module_name"].asCString());
                        std::string config_file = (*entry)["module_data_path"].asString().substr((*entry)["module_data_path"].asString().find_last_of("\\") + 1, (*entry)["module_data_path"].asString().length() - (*entry)["module_data_path"].asString().find("\\"));
                        if (config_file.length() != 0)
                            ImGui::TextWrapped(u8"配置文件:\n%s", config_file.c_str());
                        else
                        {
                            ImGui::TextWrapped(u8"配置文件:\n%s", (*entry)["module_data_path"].asCString());
                        }
                        ImGui::Text(u8"状态:%s", (*entry)["active"].asBool() ? u8"已启动" : u8"未启动");

                        if (!(*entry)["active"].asBool())
                        {
                            std::string open_text = u8"启动:";
                            open_text += (*entry)["module_name"].asString();
                            if (ImGui::Button(open_text.c_str())) {
                                (*entry)["active"] = true;
                                mode = (*entry)["module_id"].asInt();
                                cfg->json["plugins"]["mode"] = mode;
                                load_module_decelaration(cfg, mode);

                                l2d_scale = cfg->json["decoration"]["l2d_correct"].asFloat();
                                l2d_position_x = cfg->json["decoration"]["l2d_offset"][0].asFloat();
                                l2d_position_y = cfg->json["decoration"]["l2d_offset"][1].asFloat();

                                rightarmLine.x = static_cast<float>(cfg->json["decoration"]["armLineColor"][0].asInt()) / 255.0;
                                rightarmLine.y = static_cast<float>(cfg->json["decoration"]["armLineColor"][1].asInt()) / 255.0;
                                rightarmLine.z = static_cast<float>(cfg->json["decoration"]["armLineColor"][2].asInt()) / 255.0;

                                hand_position_x = cfg->json["decoration"]["hand_offset"][0].asInt();
                                hand_position_y = cfg->json["decoration"]["hand_offset"][1].asInt();

                                DataSender(*client, ModeChange, cfg);
                            }
                        }

                        if ((*entry)["active"].asBool()) {
                            if (ImGui::Button(u8"资源重载")) {
                                load_module_decelaration(cfg, mode);

                                l2d_scale = cfg->json["decoration"]["l2d_correct"].asFloat();
                                l2d_position_x = cfg->json["decoration"]["l2d_offset"][0].asFloat();
                                l2d_position_y = cfg->json["decoration"]["l2d_offset"][1].asFloat();

                                rightarmLine.x = static_cast<float>(cfg->json["decoration"]["armLineColor"][0].asInt()) / 255.0;
                                rightarmLine.y = static_cast<float>(cfg->json["decoration"]["armLineColor"][1].asInt()) / 255.0;
                                rightarmLine.z = static_cast<float>(cfg->json["decoration"]["armLineColor"][2].asInt()) / 255.0;

                                hand_position_x = cfg->json["decoration"]["hand_offset"][0].asInt();
                                hand_position_y = cfg->json["decoration"]["hand_offset"][1].asInt();

                                DataSender(*client, Reload, cfg);

                            }

                            ImGui::SameLine();
                            ImGui::PushItemFlag(ImGuiItemFlags_Disabled, (bool)open_file);
                            if (ImGui::Button(u8"重设配置文件")) {
                                std::vector<std::string> filters = { "json","*.json" };
                                open_file = std::make_shared<pfd::open_file>(u8"选择猫咪配置文件", "data", filters);
                            }
                            if (open_file && open_file->ready())
                            {
                                auto result = open_file->result();
                                if (result.size())
                                    (*entry)["module_data_path"] = result[0];
                                open_file = nullptr;
                                load_module_decelaration(cfg, mode);

                                l2d_scale = cfg->json["decoration"]["l2d_correct"].asFloat();
                                l2d_position_x = cfg->json["decoration"]["l2d_offset"][0].asFloat();
                                l2d_position_y = cfg->json["decoration"]["l2d_offset"][1].asFloat();

                                rightarmLine.x = static_cast<float>(cfg->json["decoration"]["armLineColor"][0].asInt()) / 255.0;
                                rightarmLine.y = static_cast<float>(cfg->json["decoration"]["armLineColor"][1].asInt()) / 255.0;
                                rightarmLine.z = static_cast<float>(cfg->json["decoration"]["armLineColor"][2].asInt()) / 255.0;

                                hand_position_x = cfg->json["decoration"]["hand_offset"][0].asInt();
                                hand_position_y = cfg->json["decoration"]["hand_offset"][1].asInt();

                                DataSender(*client, Reload, cfg);
                            }
                            ImGui::PopItemFlag();

                            ImGui::SameLine();
                            if (ImGui::Button(u8"编辑配置文件")) {
                                isShowEditor = true;
                                std::string standard_module_path;
                                for (auto entry = cfg->json["plugins"]["mode_ex"].begin(); entry != cfg->json["plugins"]["mode_ex"].end(); entry++) {
                                    if ((*entry).isNull() || (*entry)["module_id"].isNull())
                                    {
                                        continue;
                                    }
                                    if (mode == (*entry)["module_id"].asInt()) {
                                        standard_module_path = (*entry)["module_data_path"].asString();
                                        break;
                                    }
                                }
                                char* data = LoadFile(standard_module_path.c_str());
                                if (data)
                                {
                                    modePath = standard_module_path;
                                    std::string str(data);
                                    editor.SetText(str);
                                    bfree(data);
                                }
                            }
                        }
                        ImGui::Separator();
                    }
                }
                //ImGui::End();
            }

            if (ShowWhat & 4)
            {
                //ImGui::Begin(u8"插件窗口", 0, window_flags);
                {
                    ImGui::Text(u8"插件列表:");
                    ImGui::Separator();
                    for (auto entry = cfg->json["plugins"]["module"].begin(); entry != cfg->json["plugins"]["module"].end(); entry++) {
                        if ((*entry).isNull() || (*entry)["module_id"].isNull())
                            continue;
                        ImGui::Text(u8"插件名称:%s", (*entry)["module_name"].asCString());
                        ImGui::Text(u8"状态:%s", (*entry)["active"].asBool() ? u8"已启动" : u8"未启动");

                        if ((*entry)["active"].asBool()) {
                            std::string close_text = u8"关闭:";
                            close_text += (*entry)["module_name"].asString();
                            if (ImGui::Button(close_text.c_str())) {
                                (*entry)["active"] = false;
                                DataSender(*client, Update, cfg);
                            }
                        }
                        else {
                            std::string open_text = u8"启动:";
                            open_text += (*entry)["module_name"].asString();
                            if (ImGui::Button(open_text.c_str())) {
                                (*entry)["active"] = true;
                                DataSender(*client, Update, cfg);
                            }
                        }

                        ImGui::Separator();
                    }
                }
                //ImGui::End();
            }

            if (ShowWhat & 8)
            {
                //ImGui::Begin(u8"教程窗口", 0, window_flags); 
                {
                    if (ImGui::BeginTabBar(u8"教程"))
                    {
                        if (ImGui::BeginTabItem(u8"基础教程"))
                        {
                            const std::string markdownText = u8R"(
# 欢迎使用Bongo Cat w
    使用前请阅读本教程
## 打开设置
    你可以在系统托盘区找到猫咪的图标,鼠标右键点击托盘图标可找到打开设置的选项。
    ![教程](Resources/tutorial/20200723142138.png)
## 设置
    关于猫咪的主要设置都在这个页面下。
    注意:所有的修改都会实时反馈到猫咪上面。
  ![教程](Resources/tutorial/20200723143146.png)
## 模式
    在模式列表下选择想要启动的模式。
    注意：程序同时只能启动一个模式。启动另一个模式的时候,当前模式会关闭。
  ![教程](Resources/tutorial/20200723143209.png)
    ### 资源重载
        点击资源重载来刷新当前的模型。
    ### 重设配置文件
        打开其他Bongo Cat的模型。在打开配置文件之前，请确保配置文件和猫咪的资源在同一个目录下。
    ### 编辑配置文件
        在模式选择窗口下,找到编辑配置文件。你可以在内置的配置编辑器里面修改键码。完成编辑后，请点击编辑器左上角 文件->保存 来保存配置文件。
## 插件
    插件是程序的扩展内容,你可以在插件列表里面启动或者关闭插件,插件可以同时启动多个,。
  ![教程](Resources/tutorial/20200723143344.png)
## 显示/隐藏/最小化猫咪
    当猫咪最小化后，通过点击托盘区的猫咪图标,或鼠标右键猫咪图标的菜单中点击"显示猫咪"即可恢复窗口
## 为什么猫咪启动的时候会申请管理员权限
    只有在管理员权限的时候，程序才能顺利获取高权限游戏(管理员权限启动的游戏)的键盘按键和鼠标移动的信息
)";
                            Markdown(markdownText);
                            ImGui::EndTabItem();
                        }
                        if (ImGui::BeginTabItem(u8"直播教程"))
                        {
                            const std::string markdownText = u8R"(
一些关于直播的建议。
以下建议基于 OBS Studio 25.0.0+
# 请使用OBS的游戏捕获来捕捉猫咪画面
    ## 游戏捕获捕捉不到猫咪的画面
    * OBS 缺少管理员权限,请以管理员权限重启直播软件。
    * 多显卡的情况下，尝试将猫咪和OBS运行在同一张显卡里
    * 尝试在游戏捕获的设置中勾选sli/crossfire,或多卡兼容等选项
# 背景颜色扣除
    * 在OBS游戏捕获的设置中勾选"允许透明度"来实现背景颜色的透明
  ![教程](Resources/tutorial/20200723150131.png)
    * 设置中找到背景设置，点击设置透明度,通过透明度柱状条来调节透明度。当透明度为0时，背景颜色完全去除。
    注:仅在OBS游戏捕获的"允许透明度"生效时有用。
  ![教程](Resources/tutorial/20200723150217.png)
# 避免直播软件外手动调整程序窗口的大小
    直播时调整窗口大小，会导致直播软件里的猫咪大小变化，最终导致直播布局和预期不一样。建议使用默认窗口大小。

)";
                            Markdown(markdownText);
                            ImGui::EndTabItem();
                        }
                        if (ImGui::BeginTabItem(u8"配置编辑器"))
                        {
                            const std::string markdownText = u8R"(
    猫咪的键盘点击动画是通过播放图片来实现的,以下教程将教你如何通过配置编辑器来把图片绑定到按键
# 关于配置文件
    * 配置文件需要与猫咪的资源在同一个目录下
    ![教程](Resources/tutorial/20200723160958.png)
    * 重设配置文件
    在模式页面找到重设配置文件来打开其他的猫咪模型
    ![教程](Resources/tutorial/20200723161411.png)
# 常用键码
    键码是程序里用来表示按键的数字
    ![教程](Resources/tutorial/20150610151328220.png)
# 配置文件中的键码与图片的关系
    * 以"程序根目录->data/standard/keyboard/"为例,可以看到其中的图片命名为0.png,1.png,2.png,3.png,...
    ![教程](Resources/tutorial/20200723153130.png)
    * 在模式选择窗口下，点击编辑配置文件来打开编辑器。
    ![教程](Resources/tutorial/20200723161640.png)
    * 然后在编辑器里面找到"standard"节点(大括号)。"standard"节点(大括号)里面找到"keyboard"。
    standard节点下keyboard括号里面的内容对应data/standard/keyboard/文件夹下的图片。如下图所示
    ![教程](Resources/tutorial/20200723154005.png)
    ![教程](Resources/tutorial/20200723154019.png)
    
    同理,对于手部,音频和表情等键位设置都是同理的。  
    * 添加修改单键
    只有一个键码的是单键
    ![教程](Resources/tutorial/20200723155659.png)
    * 添加修改组合键
    在一个中括号里面有多个键码的是组合键
    ![教程](Resources/tutorial/20200723155631.png)
    * 弃用键码
    删除中括号里面的内容来弃用键码
    ![教程](Resources/tutorial/20200723160446.png)
    如下图所示弃用sond下所有的键码
    ![教程](Resources/tutorial/20200723162006.png)
    * 保存文件
    完成编辑后，请点击编辑器左上角 文件->保存 来保存配置文件。  
)";
                            Markdown(markdownText);
                            ImGui::EndTabItem();
                        }   
                        if (ImGui::BeginTabItem(u8"Live2d模型"))
                        {
                            const std::string markdownText = u8R"(

# 关于Live2d
    Live2D是一种应用于电子游戏的绘图渲染技术，技术由日本Cybernoids公司开发。
    ![Live2d](Resources/Live2D, Cubism logo/l2dlogo.png)
# 关于Live2D Cubism Editor
    Live2D Cubism Editor 是制作live2d模型的工具。
    ![Live2d](Resources/Live2D, Cubism logo/Cubism logo orange.png)
# 如何向软件内导入自己的模型
    以Live2D Cubism Editor 4.0 Pro为例。
    * 点击文件
    ![Live2d](Resources/tutorial/20200725022000.png)
    * 找到 导出运作档->导出为moc3文件
    ![Live2d](Resources/tutorial/20200725022102.png)
    * 根据自己的需求设置导出的配置。SDK 4.0 和 SDK 3.3 都适用。
    ![Live2d](Resources/tutorial/20200725022139.png)
    * 文件名称一定要设置为cat.moc3
    ![Live2d](Resources/tutorial/20200725022204.png)
    * 打开Live2D Cubism Editor导出的目标文件夹。以data/standard文件夹为例，找到cat_model文件夹。
        * 删除cat_model文件夹下所有的内容。
        * 拖拽Live2D Cubism Editor导出的目标文件夹的内容到cat_model文件夹下。
    ![Live2d](Resources/tutorial/20200725022413.png)    
)";
                            Markdown(markdownText);
                            ImGui::EndTabItem();
                        }  
                        if (ImGui::BeginTabItem(u8"Live2d模型参数"))
                        {
                            const std::string markdownText = u8R"(

# live2d模型的参数
    * 鼠标和键盘参数
    ![参数](Resources/tutorial/20200725025523.png)
    ![参数](Resources/tutorial/20200725025538.png)
    * 手柄参数
    ![参数](Resources/tutorial/20200725025557.png)
# live2d模型的动作(motion)
    使用动作的时候需要设置组名为"CAT_motion"
    ![参数](Resources/tutorial/20200725030500.png)
# live2d模型的表情(expression)
    通过 Live2D Cubism Editor 制作的表情,可在猫咪中通过设置配置中l2d_expression的按键来播放表情。
    其中第一个表情是空表情来取消其他表情的。
)";
                            Markdown(markdownText);
                            ImGui::EndTabItem();
                        }
                        ImGui::EndTabBar();
                    }
                }
                //ImGui::End();
            }

            if (ShowWhat & 16) {
                //ImGui::Begin(u8"关于Bongo Cat w", 0, window_flags);
                //ImGui::SetWindowSize(ImVec2(400, 300), ImGuiCond_FirstUseEver);
                const std::string markdownText = u8R"(
    # 权限与免责声明

    * 本程序为自由软件;您可依据自由软件基金会所发表的GNU通用公共授权条款规定,就本程序再为发布与/或修改;无论您依据的是本授权的第二版或（您自行选择的）任一日后发行的版本。
    * 本程序是基于使用目的而加以发布,然而不负任何担保责任。详情请参照GNU通用公共授权。
    * 本软件中所使附带的白色猫咪形象（bongo cat）仅作为演示,非软件作者原创。如有商用需要,强烈建议修改原始猫咪的形象。
    
    Bongo Cat w, 插件猫
    Copyright (C) 2020 wengyd2016@126.com
)";
                Markdown(markdownText);
                //ImGui::End();
            }

            ImGui::EndChild();
            ImGui::End();           
          
           
            }          

            if (isShowTool) {
                
                ImGui::Begin(u8"Bongo Cat 工具栏", 0, window_flags | ImGuiWindowFlags_NoMove| ImGuiWindowFlags_NoResize|ImGuiWindowFlags_NoBackground);
                {   ImGui::SetWindowSize(ImVec2(120, 65), ImGuiCond_Always);
                    if (!GetWindowRect(MainWindowHandle, &rct)) 
                    {
                        Exist = true;
                    }
                    static bool isFirst = true;
                    if (isFirst) {
                        glfwGetWindowPos(window, &position_x, &position_y);
                        ImGui::SetWindowPos(ImVec2(position_x, position_y)); 
                        isFirst = false;
                    }                    

                    myImg* close = load_texture(std::string("Resources/close.png"));
                    if (ImGui::ImageButton((void*)close->image_texture, ImVec2(close->image_width, close->image_height)))
                    {                      
                        Exist = true;
                    }
                    ImGui::SameLine();
                    myImg* setting = load_texture(std::string("Resources/icon_gear.png"));
                    if (ImGui::ImageButton((void*)setting->image_texture, ImVec2(setting->image_width, setting->image_height)))
                    {
                        if (isShowSettiong) {                           
                            isShowSettiong = false;
                            //glfwGetWindowPos(window, &position_x, &position_y);                           
                        }
                        else {
                            isShowSettiong = true;
                            //glfwSetWindowPos(window, position_x, position_y);
                        }
                    }                    
                }
                ImGui::End();
            }          

            if (isShowEditor) {
                auto cpos = editor.GetCursorPosition();
                ImGui::Begin(u8"配置编辑器", &isShowEditor, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_MenuBar| ImGuiWindowFlags_NoDocking| ImGuiWindowFlags_NoCollapse);
                ImGui::SetWindowSize(ImVec2(800, 600), ImGuiCond_FirstUseEver);                
                if (ImGui::BeginMenuBar())
                {
                    if (ImGui::BeginMenu(u8"文件"))
                    {
                        if (ImGui::MenuItem(u8"保存"))
                        {
                            auto textToSave = editor.GetText();                           
                            std::string standard_module_path;
                            for (auto entry = cfg->json["plugins"]["mode_ex"].begin(); entry != cfg->json["plugins"]["mode_ex"].end(); entry++) {
                                if ((*entry).isNull() || (*entry)["module_id"].isNull())
                                    continue;
                                if (mode == (*entry)["module_id"].asInt()) {
                                    standard_module_path = (*entry)["module_data_path"].asString();
                                    break;
                                }
                            }
                            wchar_t* wstr = (wchar_t*)bmalloc(255);
                            size_t wstrsize = utf8_to_wchar(standard_module_path.c_str(), 0, wstr, 255);
                            wstr[wstrsize] = '\0';

                            std::ofstream os;
                            os.open(wstr, std::ios::out | std::ios::trunc);
                            if (os.good()) {
                                os.write(textToSave.c_str(), textToSave.size());
                            }
                            os.close();
                            bfree(wstr);                                                  
                        }
                        if (ImGui::MenuItem(u8"退出"))
                            isShowEditor = false;
                        ImGui::EndMenu();
                    }
                    if (ImGui::BeginMenu(u8"编辑"))
                    {
                        bool ro = editor.IsReadOnly();
                        if (ImGui::MenuItem(u8"只读模式", nullptr, &ro))
                            editor.SetReadOnly(ro);
                        ImGui::Separator();

                        if (ImGui::MenuItem(u8"撤销", "Ctrl-Z", nullptr, !ro && editor.CanUndo()))
                            editor.Undo();
                        if (ImGui::MenuItem(u8"重做", "Ctrl-Y", nullptr, !ro && editor.CanRedo()))
                            editor.Redo();

                        ImGui::Separator();

                        if (ImGui::MenuItem(u8"复制", "Ctrl-C", nullptr, editor.HasSelection()))
                            editor.Copy();
                        if (ImGui::MenuItem(u8"剪切", "Ctrl-X", nullptr, !ro && editor.HasSelection()))
                            editor.Cut();
                        if (ImGui::MenuItem(u8"删除", "Del", nullptr, !ro && editor.HasSelection()))
                            editor.Delete();
                        if (ImGui::MenuItem(u8"粘贴", "Ctrl-V", nullptr, !ro && ImGui::GetClipboardText() != nullptr))
                            editor.Paste();

                        ImGui::Separator();

                        if (ImGui::MenuItem(u8"全选", nullptr, nullptr))
                            editor.SetSelection(TextEditor::Coordinates(), TextEditor::Coordinates(editor.GetTotalLines(), 0));

                        ImGui::EndMenu();
                    }

                    ImGui::EndMenuBar();
                }

                ImGui::Text("%6d/%-6d %6d lines  | %s | %s | %s | %s", cpos.mLine + 1, cpos.mColumn + 1, editor.GetTotalLines(),
                    editor.IsOverwrite() ? "Ovr" : "Ins",
                    editor.CanUndo() ? "*" : " ",
                    editor.GetLanguageDefinition().mName.c_str(), modePath.c_str());

                editor.Render("TextEditor");
            ImGui::End();
            }                                
        }       

        // Rendering
        ImGui::Render();
        int display_w, display_h;
        glfwGetFramebufferSize(window, &display_w, &display_h);
        glViewport(0, 0, display_w, display_h);
        glClearColor(clear_color.x, clear_color.y, clear_color.z, clear_color.w);
        glClear(GL_COLOR_BUFFER_BIT);
        ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

        if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
        {
            GLFWwindow* backup_current_context = glfwGetCurrentContext();
            ImGui::UpdatePlatformWindows();
            ImGui::RenderPlatformWindowsDefault();
            glfwMakeContextCurrent(backup_current_context);
        }

        glfwSwapBuffers(window);   

        if (!isHostLive) 
        {
            glfwSetWindowShouldClose(window,true);
        }
    
    }  

    NotificationIcon::GetInstance()->Stop();
    // Cleanup
    ImGui_ImplOpenGL3_Shutdown();
    ImGui_ImplGlfw_Shutdown();
    ImGui::DestroyContext();

    glfwDestroyWindow(window);

    cat_live2d_release();
    img_holder.clear();

    client->SendData(DisConnect, "", 0);
    return;
}

void catimgui::SetIsShowTool(bool set)
{
    isShowTool = set;
}

void catimgui::SetIsSetting()
{
    isShowSettiong ? isShowSettiong = false : isShowSettiong = true;
}

void catimgui::SetIsExist(bool set)
{
    Exist = set;
}
